<?php

// $Id: helpers.inc,v 1.1.2.13 2008/09/19 00:05:29 mercmobily Exp $

###############################################################
##                   MISC FUNCTIONS
###############################################################

/**
 * Work out the $section variable. The URLs can be /Section  or
 * /upcoming/XXX/Section 
 * 
 * @return
 *   The name of the section (the safe_section version)
*/
function drigg_get_section_from_url() {
  $section = '';

  // Case #1: the url is /Section/ ...
  if (drigg_is_section_valid(arg(0))) { 
    $section = arg(0); 
  }

  // Case #2: the url is /upcoming|published|archived/XXX/Section
  if (( arg(0) == 'upcoming' || arg(0) == 'published' || arg(0) == 'archived') && drigg_is_section_valid(arg(2))) {
    $section = arg(2);
  } 

  // Case #2: the url is /node/XXX and the node type is
  // a drigg node
  if (arg(0) == 'node' && is_numeric(arg(1))) {
    $n = node_load(arg(1));
    if ($n->type == 'drigg') {
      $section = $n->safe_section;
    }
  }
  return $section;
}

/**
 * It returns the home page (the main page, no subfolders) of a
 * URL. For example, http://www.drigg.org/something/else becomes
 * http://www.drigg.org. This is convenient to be used while
 * displaying a node
 *
 * @param $url
 *   The URL to process
 * @return
 *   The resulting URL
*/
function drigg_format_url_home($url) {
  $url = preg_replace('%^(https?://[^/]*).*%', '\1', $url);
  return $url;
}

/**
 * Theme function for the home URL
 *
 * @param $url
 *   The URL to process
 * @return
 *   The resulting URL
 */
function theme_format_url_home($url) {
  $url = drigg_format_url_home($url);

  return l($url, $url, array('rel' => t('nofollow')));
}

/**
 * This function makes absolute sure that a string that contains a list
 * of numbers ("1,45,44,2,34,5") is _perfect_. THat is: each thing is
 * actually a number, etc.
 *
 * @param $string
 *   The string to check
 * @return
 *   The same string, after normalisation
*/
function drigg_fix_number_list($string) {
    return implode(',', array_filter(explode(',', $string), "drigg_is_number_proc"));
}

/**
 * Support function for drigg_fix_number_list
 * FIXME: This needs to do things with a regexp.
 *
 * @param $element
 *   An element to be tested
 * @return
 *   TRUE if it's a number (not 0), FALSE otherwise
*/
function drigg_is_number_proc($element) {
  if ($element == '' || $element == '0') {
    return FALSE;
  }
  if (!(is_numeric($element))) {
    return FALSE;
  }
  return TRUE;
}

/**
 * Returns the nodes with a specific term.
 *
 * @param $tid
 *   The term id
 * @return
 *   The $result of db_query
*/
function drigg_select_nodes_by_term($tid) {
 
  $result = db_query(db_rewrite_sql("SELECT DISTINCT(n.nid), n.sticky, n.title, n.created FROM {node} n INNER JOIN {term_node} tn ON n.nid = tn.nid WHERE tn.tid IN (%d) ORDER BY n.sticky DESC, n.created DESC", 'node', 'nid'), $tid);

  return $result;
}


function drigg_clean_utf($str) {
  if (!function_exists('iconv')) {
    return $str;
  }
  else {
    return iconv("UTF-8", "UTF-8//IGNORE", $str);
  }
}

##############################################################
#       FUNCTIONS TO GENERATE VOTINGAPI QUERIES & INFO
##############################################################

function drigg_votingapi_query($field_name, $filter_function = TRUE) {

  // Get the VotingAPI settings

  list($content_type, $value_type, $tag, $function) = drigg_votingapi_variables();

  // Make up the query
  $r = "1 = 1 AND ${field_name}.content_type = '$content_type' AND ${field_name}.value_type = '$value_type' AND ${field_name}.tag = '$tag' ";
  if ($filter_function) {
    $r .= "AND ${field_name}.function = '$function' ";
  }
 
  return $r; 
}

function drigg_votingapi_variables() {
  return array( 
     variable_get('drigg_votingapi_content_type', 'node'),
     variable_get('drigg_votingapi_value_type', 'points'),
     variable_get('drigg_votingapi_tag', 'vote'),
     variable_get('drigg_votingapi_function', 'sum')
  );
}

#########################################################
##       LOCAL/REMOTE URL FUNCTIONS USED IN THEMES
#########################################################

function drigg_link(&$node) {
  if (drigg_url_is_local($node)) {
    return url($node->url);
  }
  else {
    return $node->url;
  }
}

function drigg_url_is_local(&$node) {
  if (substr($node->url, 0, 5) == 'node/') {
    return TRUE;
  }
  return FALSE;
}

###############################################################
##               URL-CHECKING FUNCTIONS
###############################################################

/**
 * Check if a URL is valid
 *
 * @param $url
 *   The URL to check
 * @return
 *   FALSE if it's not valid, TRUE otherwise
*/
function drigg_url_valid($url) {
 
  // First of all, it needs to be a valid URL starting with http://
  if (substr($url, 0, 7) != "http://" && substr($url, 0, 8) != "https://") {
    return FALSE;
  }

  // Parse the URL
  $url_parsed = parse_url($url);

  #foreach ($url_parsed as $key => $element) {
  #  drupal_set_message("$key -> ". $element);
  #}

  // The host needs to be there, user and password must be unset
  if ($url_parsed['host'] == "" || $url_parsed['user'] != "" || $url_parsed['pass'] != "") {
    return FALSE;
  }

  // All clear!
  return TRUE;
}

/**
 * Check if a URL actually works
 * NOTE: it's absolutely crucial that the results from this call
 * are cached, because otherwise between preview and submitting, the
 * retrieving of the URLs happens twice. The function is smart enough
 * to strip most of the return data so that not much $SESSION is wasted
 *
 * @param $url
 *   The URL to check
 * @return
 *   NULL if it doesn't work, the $request object otherwise
*/
function drigg_url_http_ok($url, $method = 'HEAD', $cache = TRUE) {

  #drupal_set_message("Requested HTTP URL: '$url', method: '$method'");


  // Check that the page wasn't already cached! If so, return what was
  // in the cache
  if ($cache) {
    $request_cache = $_SESSION['drigg_request_cache'];
    if ($request_cache[$url . $method]) {
      #drupal_set_message("Serving cached result for '$url',method: '$method'");
      return $request_cache[$url . $method];
    }
  }

  // Not cached: do the actual request
  #drupal_set_message("The URL '$url', method '$method' was not cached. ");
  $url_request = drupal_http_request($url, array(), $method);
  if ($url_request->code != 200 && $url_request->redirect_code != 200) {
    #drupal_set_message("HTTP request for URL FAILED");
    return NULL;
  }

  // Strip the result, apart from the trackback bit
  if ($method != 'HEAD') {
    $url_request->data = preg_replace('/.*(<rdf:RDF.*trackback:ping="[^"]+".*<\/rdf:RDF>).*/s', '\1', $url_request->data); 
  }

  // Write it onto the cache
  if ($cache) {
    // Set the session cache
    $_SESSION['drigg_request_cache'][$url . $method] = $url_request;
  }

  // Return the result
  return $url_request;
}

/**
 * Check if a URL exists
 *
 * @param $url
 *   The URL to check
 * @param $nid_to_ignore
 *   The NID to ignore. This is very handy when editing of a node is
 *   going on (the URL will obviously exist already...)
 * @return
 *   FALSE if it doesn't exist, TRUE otherwise
*/
function drigg_url_exists($url, $nid_to_ignore = 0, $no_hooks=FALSE) {

  if (!$no_hooks) {
    module_invoke_all('drigg_pre_url_exists', $url, $nid_to_ignore);
  }

  // Create the bit of the query that reals with Nid
  if ($nid_to_ignore != 0) {
    $nid_query = " AND dnid <> $nid_to_ignore";
  }

  $sql = "SELECT * FROM {drigg_node} dn LEFT JOIN {node} n on dn.dnid = n.nid WHERE dn.url='%s'". $nid_query;
  $result = db_fetch_object(db_query($sql, $url));
  if (!$result) {
    return 0;
  }

  if (!$no_hooks) {
    module_invoke_all('drigg_post_url_exists', $url, $nid_to_ignore, $result);
  }

  #drupal_set_message("DEBUG: Existing (duplicate) node: $result");
  return $result; 
}

/**
 * Check if a URL is banned. Banning happens in the configuration
 * options
 *
 * @param $url
 *   The URL to check
 * @return
 *   FALSE if it is banned. TRUE otherwise
*/
function drigg_url_banned($url) {

  // Get the list of URLs from the list
  $urls_a = split("\n", variable_get('drigg_banned_urls', ''));

  // Check that NO URL belongs to the list
  foreach ($urls_a as $url_in_list) {

    $url_in_list = rtrim($url_in_list);

    // Make up a version of the URL as long as the blacklisted entry
    $url_s = substr($url, 0, strlen($url_in_list));

    #drupal_set_message("BLACKLISTED: $url_in_list");
    #drupal_set_message("url_s IS $url_s compared to $url_in_list");

    // The URL is blacklisted!
    if ($url_s == $url_in_list && $url_s != '') {
      return TRUE;
    }
      
  }

  return FALSE; 
}

##################################################################
##                SCOOP STATUS FETCHING FUNCTIONS
##################################################################

/**
 * Returns the "promoted" string
 *
 * @param $node
 *   The node object to consider
 * @param $granularity
 *   The granularity
 * @return
 *   The string
*/
function drigg_promoted_string($node, $granularity = 2) {
  if (!$node->promote) {
    return '';
  }
  return t('Made popular !interval ago', array('!interval' => format_interval(time() - $node->promoted_on, $granularity)));
}

/**
 * Returns the "created" string 
 *
 * @param $node
 *   The node object to consider
 * @param $granularity
 *   The granularity
 * @return
 *   The string
*/

function drigg_created_string($node, $granularity = 2) {
  return t('!interval ago', array('!interval' => format_interval(time() - $node->created, $granularity)));
}

/**
 * Returns the link to the section a drigg node belongs to 
 *
 * @param $node
 *   The node object to consider
 * @return
 *   The link
*/
function drigg_section_link($node,$type='tag') {
  $section_name = drigg_section_name_by_safe_name($node->safe_section);
  if($type == 'tag'){
    $section_id = drigg_section_id_by_safe_name($node->safe_section);
    return l($section_name, 'taxonomy/term/'. $section_id);
  } else {
    return l($section_name, $node->safe_section);
  }

}

/**
 * Support function for drigg_user_scoops.
 * 
 *
 * @param $node
 *   The node
 * @return
 *   The status: promoted, archived or queued
*/
function drigg_scoop_status_string($node) {

 // Work out the $t(ime) variable, used in a minute to compare
 $t = time() - 60 * 60 * variable_get('drigg_hours_in_upcoming', 0);

  // Crates the created_str
  if ($node->promote) {
    return t('promoted');
  }
  else {
    if ($node->created < $t) {
      return t('archived');
    }
    else {
      return t('queued');
    }
  }
}

##################################################################
##             SECTIONS FUNCTIONS - LOOKUP AND LOAD
##################################################################

/**
 * Function to load the function list into memory. The list is then
 * placed into a static variable. It's therefore cached - this is
 * crucial to prevent too many DB calls.
 * 
 * @return
 *   An associative array filled with all of the sections.
*/
function drigg_section_list($rebuild_cache = FALSE) {

  static $cache;

  $disallowed_section = variable_get('drigg_disallowed_term_id', '0');

  #drupal_set_message("Drigg_section_list called, cache is $cache, rebuild cache is $rebuild_cache"); 

  // Only do it if it's the first time it's been called
  if (!$cache || $rebuild_cache) {
 
    #drupal_set_message("HERE!"); 
    //$result_t = db_query('select * from {term_data} where vid=%d ORDER BY weight', variable_get('drigg_section_vid', -1));
    $result_t = db_query('SELECT * FROM {term_data} td 
      LEFT JOIN {term_hierarchy} th ON td.tid = th.tid 
      WHERE td.vid=%d 
      ORDER BY weight,th.tid',variable_get('drigg_section_vid', -1));

    while ($term = db_fetch_object($result_t)) {

      if ($term->tid == $disallowed_section ) {
        continue;
      }

      $tid = $term->tid;
      $parent_tid = $term->parent;
      $name = $term->name;
      $safe_name = drigg_safe_term_name($name);
      $description = $term->description;
      $weight = $term->weight;

      // SET BY TID
      $cache['lookup'][$tid]['name'] = $name;
      $cache['lookup'][$tid]['safe_name'] = $safe_name;
      $cache['lookup'][$tid]['description'] = $description;
      $cache['lookup'][$tid]['weight'] = $weight;
      $cache['lookup'][$tid]['tid'] = $tid;
      $cache['lookup'][$tid]['parent_tid'] = $parent_tid; ##proper section hierarchy

      $cache['by_weight'][] = $tid;
      $cache['by_safe_name'][$safe_name] = $tid;

      $cache['for_select'][$tid] = $name;
      #drupal_set_message("$tid, $name");
    }
  }
  return $cache;
}

/**
 * Function to work out the "safe name" of a section from its name.
 * The safe name is used in URLs
 *
 * @param $name
 *   The section name
 * @return
 *   A URL-safe section name (only letters and numbers are allowed)
*/
function drigg_safe_term_name($name) {
    return drigg_pathauto_cleanstring($name, variable_get('drigg_separator_categories', ''), FALSE);
    #return preg_replace('/[^a-zA-Z0-9]/', '', $name);
}

/**
 * Function to work out if the "safe name" is actually valid - that is,
 * if it's been defined in a Drupal's menu
 *
 * @param $safe_name
 *   The section's safe name
 * @return
 *   TRUE if the section's safe name is valid
*/
function drigg_is_section_valid($safe_name) {

  // This is handy, just in case. An empty section is not "valid"
  if ($safe_name == '') {
    return FALSE;
  }

  // Return it!
  $terms = drigg_section_list();
  return ($terms['by_safe_name'][$safe_name]);
}

/**
 * Function to work out the section's full name from its safe name
 *
 * @param $safe_name
 *   The section's safe name
 * @return
 *   The section's full name
*/
function drigg_section_name_by_safe_name($safe_name) {
  $terms = drigg_section_list();
  return $terms['lookup'][$terms['by_safe_name'][$safe_name]]['name'];
}

##################################################
#           DEBUG MESSAGES FUNCTIONS
##################################################

function drigg_debug_msg($msg) {
  global $user;

  if (variable_get('drigg_debug', FALSE) && $user->uid == 1) {
    drupal_set_message("DEBUG: $msg");
  }
}

function drigg_admin_msg($string) {
  global $user;

  if ($user->uid == 1) {
    drupal_set_message($string, 'error');
  }
}

/**
 * Function to work out the section's id from its safe name
 *
 * @param $safe_name
 *   The section's safe name
 * @return
 *   The section's id
*/
function drigg_section_id_by_safe_name($safe_name) {
  $terms = drigg_section_list();
  return $terms['by_safe_name'][$safe_name];
}

/**
 * Set the "promote" flag of a node (in the node table), and the "promoted_on"
 * field (in the drigg_node table)
 *
 * @param $nid
 *   The node id of the node to be promoted
*/
function drigg_promote_node($nid) {
  db_query("UPDATE {node} n SET n.promote = 1 WHERE n.nid = %d", $nid);
  db_query("UPDATE {drigg_node} n SET n.promoted_on = %d WHERE n.dnid = %d", time(), $nid);
}


##################################################
#             PURE THEFT!!! :-D
##################################################

/**
 * Function stolen from the pathauto() module
 * This is because people might not want to include path/pathauto
 * just for this function (pathauto creates a LOT of queries)
 *
 * @param $string
 *   The URL
 * @return
 *   A clean string you can use for the URLs title
*/
function drigg_pathauto_cleanstring($string, $separator='_', $randomize=FALSE) {
  // Default words to ignore
  $ignore_words = array(
    "a", "an", "as", "at", "before", "but", "by", "for", "from",
    "is", "in", "into", "like", "of", "off", "on", "onto", "per",
    "since", "than", "the", "this", "that", "to", "up", "via",
    "with"
  );

  static $i18n_loaded = false;
  static $translations = array();
  if (!$i18n_loaded) {
    $path = drupal_get_path('module', 'drigg');
    if (is_file($path .'/i18n-ascii.txt')) {
      $translations = parse_ini_file($path .'/i18n-ascii.txt');
    }
    $i18n_loaded = true;
  }

  $output = strtr($output, $translations);

  // Replace or drop apostrophes based on user settings
  $quotes = 0;
  $output = str_replace("'", ($quotes ? $separator : ''), $string);
  
  $output = strtr($output, $translations);

  // Get rid of words that are on the ignore list
  $ignore_re = "\b". preg_replace("/,/", "\b|\b", $ignore_words) ."\b";
  $output = preg_replace("/$ignore_re/ie", "", $output);

  // Preserve alphanumerics, everything else becomes a separator
  $pattern = '/[^a-zA-Z0-9]+/ ';
  $output = preg_replace($pattern, $separator, $output);

  // Trim any leading or trailing separators (note the need to
  // escape the separator if and only if it is not alphanumeric)
  if ($separator) {
    if (ctype_alnum($separator)) {
      $seppattern = $separator;
    } 
    else {
      $seppattern = '\\'. $separator;
    }
    $output = preg_replace("/^$seppattern+|$seppattern+$/", "", $output);
  }

  // Enforce the maximum component length
  $maxlength = 256;
  $output = drupal_substr($output, 0, $maxlength);

  // Last minute check: if the result is empty, then return a random
  // number. This is important in case you get something like this as title:
  // எனக்கு வாய்கண்ட மருந்து - திரிபலா
  if ($output === '') {

    $output = drupal_substr($string, 0, $maxlength);

    // Randomisation was requested. This is used for story titles (for
    // now). return a random number!
    if ($randomize) {
      $output = rand(1, 2000000);

    // Randomisation was NOT requested. This is used for category
    // names. This is theoretically dangerous, because (for example)
    // a name like "///////" would create broken paths. BUT! It is
    // only used for terms. So, it's up to the admin not to fuck up
    }
    else {
      #$output = drupal_substr($output, 0, $maxlength);
      $output = $string;
    }
  }

  return $output;
}
